今天預計和大家一起看看:
好的,那我們就開始吧!
main.dart中的code如何構成模擬器上的畫面:最上方我們看到 main() function
main() 是dart裡面最高層級的function,一個dart應用程式只能使用一次,作為整個dart app啟動的入口。
我們可以看到這個main裡面執行的是runApp。runApp是flutter框架提供的method,啟動我們提供的Widget並運行在畫面上。
這邊我們傳入的組件是使用MyApp class的constructor 建構的新的instance:MyApp()
接著我們就看到main()裡面使用的MyApp class的定義:
MyApp 繼承了StatelessWidget(無狀態組件,於下一章說明)本身和其所繼承的所有實踐,並且覆寫了build方法。
在Widget中,build method用於組建UI元件,交由flutter偵測UI結構後產生結構樹渲染於頁面上。
Flutter提供兩種App的設計風格指南:Material Design(Android App)為主的MaterialApp,和Human Interface Guideline(iOS APP)為主的CupertinoApp(Cupertino是Apple總部所在的城市)。我們可以依照需求決定要採用哪種設計風格。
這裏MyApp的build()回傳了一個新的MaterialApp並且提供了參數:
MyHomePage是一個StatefulWidget(有狀態組件,同樣於下一章說明),包括MyHomePage和_MyHomePageState兩個部分:

MyHomePage class定義了建構一個實例所需的參數:title,指定required this.title代表建構時,title為必需輸入的值,而輸入的參數會被存在實例中的title field之中。
而MyHomePage繼承的StatefuleWidget有定義createState method,用於產生狀態管理實例,MyHomePage的狀態管理組件就是 private class _MyHomePageState。

在_MyHomePageState中紀錄了
_counter儲存計數,_incrementCounter來增加計數值。build之中終於看到了本篇的主角:Scaffold作為整個頁面的主要結構。在這裡的Scaffold有三個主要的部分:
appBar:主標題橫幅,body:頁面主體,floatingActionButton:右下角的按鍵我們也可以看到_incrementCounter被塞在 FloatingActionButton 的onPress之中、整個FloatinActionButton也包著一個+號的Icon :Icon(Icons.add),這也解釋了頁面上點擊"+"之後會增加頁面上計數的行為。
由上面的敘述,可以看出啟動APP之後我們看到的其實是MyHomePage堆疊各種組件所產生畫面。
Flutter強調一個重點概念:
Everything is a Widget
所有的頁面都是由一個一個的Widget(組件)構成,就跟樂高一樣,只要有恰當的積木,就可以組成任何的樣子。
值得一提的是,連「置中」、「對齊」、「外觀樣式」這類的排版概念,在Flutter裡面也是Widget:你可以建構一個自訂Widget A,再把Widget A用置中組件Center包起來
Center(
children: const A();
)
這樣A組件就可以置中了,是不是非常神奇?
而Scaffold的本意是支架,也就是它扮演了一個頁面支架的角色。要建構一個Scaffold Widget可以依照需求輸入各種參數,比如說_MyAppState用了appBar, body, floatingActionButton來構成頁面主體

下面列舉一些scaffold常用的區塊:
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '首頁',
tooltip: '',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: '設定',
tooltip: '',
),
],
),
drawer: Drawer(
child: ListView(
children: const <Widget>[
ListTile(
leading: Icon(Icons.access_alarm),
title: Text('Alarm'),
),
],
),
),
定義上滑式選單
bottomSheet: BottomSheet(
builder: (context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: const <Widget>[
ListTile(
leading: Icon(Icons.photo),
title: Text('Open Camera'),
),
ListTile(
leading: Icon(Icons.photo_album),
title: Text('Use Picture from Gallery'),
)
],
);
},
onClosing: () => {},
),
關於Scaffold更多的操作可以在Scaffold class裡面找到
大致了解了Scaffold,我們就來針對這次的專案需求實地更改程式碼吧:
移除不必要的FloatingButton
清空頁面主體和計數器邏輯,先用空白的區塊(Container)代替
新增底部的bottomNavigationBar並新增三個頁面選項
新增底部bottomNavigationBar的設定
selectedItemColor: 項目被選取時呈現的顏色selectedFontSize: 項目被選取時呈現的字體大小unselectedFontSize: 項目未被選取時呈現的字體大小unselectedItemColor:項目未被選取時呈現的字體顏色currentIndex: 目前被選取的是第幾個項目BottomNavigationBarType: 定義項目大小是固定(BottomNavigationBarType.fixed)或浮動(BottomNavigationBarType.shift),更動AppBar標題為:「今日照片」
本次改動的相關程式碼放在 我的github,見Day9相關commit
頁面呈現
今天我們看到了:
Scaffold:快速地組織一個頁面的結構
appBar:頁面上方橫幅body:頁面主體floatingButton:頁面懸浮按鈕bottomNavigationBar:底部的導頁選單drawer:側邊欄bottomSheet:上滑式選單明天我們一起來看看頁面的狀態管理,了解StatelessWidget和StatefuleWidget!